﻿using System;
using Spk.Controls.Common;

namespace Spk.Controls.Trees
{
    public partial class VirtualTreeView
    {
        // Proxy structures --------------------------------------------------

        public class NodeProxies
        {
            // Protected fields ----------------------------------------------

            /// <summary>
            /// Visibility of node
            /// </summary>
            public readonly NodeVisibleProxy Visible;

            /// <summary>
            /// User data attached to node
            /// </summary>
            public readonly NodeDataProxy Data;

            /// <summary>
            /// Height of a node
            /// </summary>
            public readonly NodeHeightProxy Height;

            /// <summary>
            /// Nesting level of node
            /// </summary>
            public readonly NodeLevelProxy Level;

            /// <summary>
            /// Determines selection of node
            /// </summary>
            public readonly NodeSelectedProxy Selected;

            /// <summary>
            /// Determines the checked state of node
            /// </summary>
            public readonly NodeCheckedProxy Checked;

            /// <summary>
            /// Determines, whether node is expanded or not
            /// </summary>
            public readonly NodeExpandedProxy Expanded;

            /// <summary>
            /// Controls count of node's children
            /// </summary>
            public readonly NodeChildCountProxy ChildCount;

            /// <summary>
            /// Verifies, whether node belongs to this tree
            /// </summary>
            public readonly NodeValidProxy Valid;

            // Public classes ------------------------------------------------

            public class NodeVisibleProxy
            {
                private VirtualTreeView tree;

                public NodeVisibleProxy(VirtualTreeView newTree)
                {
                    newTree.CheckNull("tree");
                    tree = newTree;
                }

                /// <summary>
                /// Controls node's visibility.
                /// </summary>
                public bool this[VirtualNode node]
                {
                    get
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        return (node.IsVisible);
                    }
                    set
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        if (node == tree.root)
                            throw new InvalidOperationException("Internal error: cannot set visibility of the root node!");

                        if (value)
                            tree.ShowNode(node);
                        else
                            tree.HideNode(node);
                    }
                }
            }

            public class NodeDataProxy
            {
                private VirtualTreeView tree;

                public NodeDataProxy(VirtualTreeView newTree)
                {
                    newTree.CheckNull("tree");

                    tree = newTree;
                }

                /// <summary>
                /// Access to internal node's user data
                /// </summary>
                public object this[VirtualNode node]
                {
                    get
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        return node.Data;
                    }
                    set
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        node.Data = value;
                    }
                }
            }

            public class NodeHeightProxy
            {
                private VirtualTreeView tree;

                public NodeHeightProxy(VirtualTreeView newTree)
                {
                    newTree.CheckNull("newTree");

                    tree = newTree;
                }

                /// <summary>
                /// Height of the node
                /// </summary>
                public uint this[VirtualNode node]
                {
                    get
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        tree.VerifyNodeMeasured(node);

                        return node.Height;
                    }
                    set
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        if (tree.drawMode == DrawModes.Default)
                            throw new VirtualTreeViewException("Cannot set node height when draw mode is set to default!");

                        tree.SetNodeHeight(node, value);

                        node.IsMeasured = true;
                    }
                }
            }

            public class NodeLevelProxy
            {
                private VirtualTreeView tree;

                public NodeLevelProxy(VirtualTreeView newTree)
                {
                    newTree.CheckNull("tree");
                    tree = newTree;
                }

                /// <summary>
                /// Returns level of nesting for node (0 for hidden root node,
                /// 1 for its children, 2 for their children and so on)
                /// </summary>
                public uint this[VirtualNode node]
                {
                    get
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        return TreeStructure.GetNodeLevel(node);
                    }
                }
            }

            public class NodeSelectedProxy
            {
                private VirtualTreeView tree;

                public NodeSelectedProxy(VirtualTreeView newTree)
                {
                    newTree.CheckNull("tree");
                    tree = newTree;
                }

                /// <summary>
                /// Controls node's selection state
                /// </summary>
                public bool this[VirtualNode node]
                {
                    get
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        return node.IsSelected;
                    }
                    set
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        if ((node.IsSelected) != value)
                        {
                            if (value)
                            {
                                if (tree.multiSelect)
                                    tree.AddToSelection(node);
                                else
                                    tree.SetSelection(node);
                            }
                            else
                            {
                                tree.RemoveFromSelection(node);
                            }
                        }
                    }
                }
            }

            public class NodeCheckedProxy
            {
                private VirtualTreeView tree;

                public NodeCheckedProxy(VirtualTreeView newTree)
                {
                    newTree.CheckNull("tree");
                    tree = newTree;
                }

                /// <summary>
                /// Controls node's checked state
                /// </summary>
                public bool this[VirtualNode node]
                {
                    get
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        return node.IsChecked;
                    }
                    set
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        tree.SetChecked(node, value);
                    }
                }
            }

            public class NodeExpandedProxy
            {
                private VirtualTreeView tree;

                public NodeExpandedProxy(VirtualTreeView newTree)
                {
                    newTree.CheckNull("tree");
                    tree = newTree;
                }

                /// <summary>
                /// Controls node's expand state.
                /// </summary>
                public bool this[VirtualNode node]
                {
                    get
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        tree.VerifyNodeUserInitialized(node);

                        return (node.IsExpanded);
                    }
                    set
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        if ((node.IsExpanded) != value)
                        {
                            if (value)
                                tree.ExpandNode(node);
                            else
                                tree.CollapseNode(node);
                        }
                    }
                }
            }

            public class NodeChildCountProxy
            {
                private VirtualTreeView tree;

                public NodeChildCountProxy(VirtualTreeView newTree)
                {
                    newTree.CheckNull("tree");
                    tree = newTree;
                }

                /// <summary>
                /// Controls node's child count.
                /// </summary>
                public uint this[VirtualNode node]
                {
                    get
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        tree.VerifyNodeUserInitialized(node);
                        tree.VerifyChildrenInitialized(node);

                        return node.ChildCount;
                    }
                    set
                    {
                        node.CheckNull("node");
                        node.CheckOwnerTree(tree, "node");

                        tree.SetChildCount(node, value);
                    }
                }
            }

            public class NodeValidProxy
            {
                private VirtualTreeView tree;

                public NodeValidProxy(VirtualTreeView newTree)
                {
                    newTree.CheckNull("tree");
                    tree = newTree;
                }

                /// <summary>
                /// Checks, if node is valid (hasn't been deleted)
                /// </summary>
                public bool this[VirtualNode node]
                {
                    get
                    {
                        return (node.OwnerTree == tree);
                    }
                }
            }

            // Public methods ------------------------------------------------

            public NodeProxies(VirtualTreeView tree)
            {
                Visible = new NodeVisibleProxy(tree);
                Data = new NodeDataProxy(tree);
                Height = new NodeHeightProxy(tree);
                Level = new NodeLevelProxy(tree);
                Selected = new NodeSelectedProxy(tree);
                Checked = new NodeCheckedProxy(tree);
                Expanded = new NodeExpandedProxy(tree);
                ChildCount = new NodeChildCountProxy(tree);
                Valid = new NodeValidProxy(tree);
            }
        }
    }
}